package catalina;

import server.base.HttpServlet;

/**
 * @ClassName Mapper
 * @Description TODO mapper组件对请求url进行拆解映射，找出对应的host\context\wrapper\servlet
 * @Auth ying.xiao
 * @Date 2021/3/12
 * @Version 1.0.0
 */
public class Mapper {

    volatile MappedHost[] hosts = new MappedHost[0];

    //根据url映射找出调用host\context\wrapper
    public void map(Request request){
        MapperData mapperData = new MapperData();
        //匹配host
        for (int i = 0; i < hosts.length; i++) {
            if(hosts[i].name.equals(request.getIp())){
                mapperData.setHost(hosts[i].object);

                //匹配成功host
                MappedHost host = hosts[i];

                //匹配context
                ContextList contextList = host.contextList;
                MappedContext[] contexts = contextList.contexts;
                for (int i1 = 0; i1 < contexts.length; i1++) {
                    if(contexts[i1].name.equals(request.getContextPath())){
                        MappedContext context = contexts[i1];
                        mapperData.setContext(context.object);


                        //匹配wrapper
                        MappedWrapper[] wrappers = context.wrappers;
                        for (int i2 = 0; i2 < wrappers.length; i2++) {
                            //精确匹配
                            if(wrappers[i2].name.equals(request.getServletUrl())){
                                MappedWrapper wrapper = wrappers[i2];
                                mapperData.setWrapper(wrapper.object);
                                break;
                            }
                        }
                    }
                }

            }
        }

        request.setMapperData(mapperData);
    }


    //添加host映射关系
    public synchronized MappedHost addHost(String name,String appBase){
        StanderHost standerHost = new StanderHost(name, appBase);
        MappedHost mappedHost = new MappedHost(name, standerHost);
        MappedHost[] newHosts = new MappedHost[hosts.length + 1];
        System.arraycopy(hosts, 0, newHosts, 0, hosts.length);
        newHosts[hosts.length] = mappedHost;
        hosts = newHosts;
        return mappedHost;
    }


    public static final class MappedHost extends MapElement<Host> {

        public volatile ContextList contextList;

        public MappedHost(String name, Host host) {
            super(name, host);
            contextList = new ContextList();
        }

    }

    public static final class ContextList {

        public  MappedContext[] contexts;

        public ContextList() {
            this(new MappedContext[0]);
        }

        private ContextList(MappedContext[] contexts) {
            this.contexts = contexts;
        }

        //添加context映射
        public MappedContext addContext(String docBase,String path) {
            StandardContext standardContext = new StandardContext(docBase, path);
            MappedContext mappedContext = new MappedContext(path, standardContext);
            MappedContext[] newContexts = new MappedContext[contexts.length + 1];
            System.arraycopy(contexts, 0, newContexts, 0, contexts.length);
            newContexts[contexts.length] = mappedContext;
            contexts = newContexts;
            return mappedContext;
        }


    }

    public static final class MappedContext extends MapElement<Context> {

        public  MappedWrapper[] wrappers = new MappedWrapper[0];

        public MappedContext(String name, Context context) {
            super(name,context);
        }

        //添加Wrapper映射
        public void addWrapper(String url, HttpServlet httpServlet) {
            StandardWrapper standardWrapper = new StandardWrapper(httpServlet,url);
            MappedWrapper mappedWrapper = new MappedWrapper(url, standardWrapper);
            MappedWrapper[] newWrappers = new MappedWrapper[wrappers.length + 1];
            System.arraycopy(wrappers, 0, newWrappers, 0, wrappers.length);
            newWrappers[wrappers.length] = mappedWrapper;
            wrappers = newWrappers;
        }
    }


    protected static class MappedWrapper extends MapElement<Wrapper> {
        public MappedWrapper(String name, Wrapper wrapper) {
            super(name, wrapper);
        }
    }

    protected abstract static class MapElement<T> {

        public final String name;
        public final T object;

        public MapElement(String name, T object) {
            this.name = name;
            this.object = object;
        }
    }
}
